import os
import re
import cv2
import time
import pickle
import struct
import random
import logging
import requests

from bs4 import BeautifulSoup
from PIL import Image

NAME = '王维'
CARDID = 420115198804030032
logger = logging.getLogger()

headers = {"User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36',
           "Connection": "keep-alive",
           'X-Requested-With': 'XMLHttpRequest'}

class StudySession:
    """
    Session相关操作
    """
    def __init__(self):
        self.cookies_dir_path = "./studycookies/"
        self.user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36'
        self.session = self._init_session()

    def _init_session(self):
        session = requests.session()
        session.headers = self.get_headers()
        return session

    def get_headers(self):
        return {"User-Agent": self.user_agent,
                "Connection": "keep-alive",
                'X-Requested-With': 'XMLHttpRequest'}

    def get_user_agent(self):
        return self.user_agent

    def get_session(self):
        """
        获取当前Session
        :return:
        """
        return self.session

    def get_cookies(self):
        """
        获取当前Cookies
        :return:
        """
        return self.get_session().cookies

    def set_cookies(self, cookies):
        self.session.cookies.update(cookies)

    def load_cookies_from_local(self):
        """
        从本地加载Cookie
        :return:
        """
        cookies_file = ''
        if not os.path.exists(self.cookies_dir_path):
            return False
        for name in os.listdir(self.cookies_dir_path):
            if name.endswith(".cookies"):
                cookies_file = '{}{}'.format(self.cookies_dir_path, name)
                break
        if cookies_file == '':
            return False
        with open(cookies_file, 'rb') as f:
            local_cookies = pickle.load(f)
        self.set_cookies(local_cookies)

    def save_cookies_to_local(self, cookie_file_name):
        """
        保存Cookie到本地
        :param cookie_file_name: 存放Cookie的文件名称
        :return:
        """
        cookies_file = '{}{}.cookies'.format(self.cookies_dir_path, cookie_file_name)
        directory = os.path.dirname(cookies_file)
        if not os.path.exists(directory):
            os.makedirs(directory)
        with open(cookies_file, 'wb') as f:
            pickle.dump(self.get_cookies(), f)
            
class login:
    '''
    登录
    '''
    def __init__(self, study_session:StudySession):
        self.study_session = study_session
        self.session = self.study_session.get_session()
        self.is_login = False
        self.refresh_login_status()
        
    def refresh_login_status(self):
        """
        刷新是否登录状态
        :return:
        """
        self.is_login = self._validate_cookies()
        
    def _validate_cookies(self):
        """
        验证cookies是否有效（是否登陆）
        通过访问个人中心列表页进行判断：若未登录，将会重定向到登陆页面。
        :return: cookies是否有效 True/False
        """
        url = 'http://www.sptce.cn/uc/index'
        try:
            resp = self.session.get(url=url,allow_redirects=False)
            if resp.status_code == requests.codes.OK:
                return True
        except Exception as e:
            logger.error("验证cookies是否有效发生异常", e)
        return False
    
    def login_by_username(self):
        codeurl = 'http://www.sptce.cn/ran/ajax/random'
        # code_html = session.get(self.login_url,headers=headers,timeout=10).content.decode('utf-8')
        valcode = session.get(codeurl)
        with open('code.jpg','wb') as fp:
            fp.write(valcode.content)
        #打开并显示图片
        img=Image.open('code.jpg')
        img.show()
        params = {'idCardNo': CARDID,
                  'realName': NAME,
                  }
        params['randomcode'] = input('输入验证码：')
        r = session.post("http://www.sptce.cn/user/ajax/getloginUser", params=params, headers=headers)
        self.refresh_login_status()
        return session
        
class CourseInfo:
    def __init__(self,session,headers,cookies):
        self.session = session
        self.headers = headers
        self.cookies = cookies

    def get_course_infos(self):
        index = self.session.get("http://www.sptce.cn/uc/index/",headers=self.headers,cookies=self.cookies)
        courses_soup = BeautifulSoup(index.content)
        course_infos = courses_soup.findAll('dd',{'class':"u-order-list"})
        video_lst = []
        for course_info in course_infos:
            video = {}
            try:
                video['percent'] = self._get_current_percent(course_info)
                video['name'] = course_info.find('a',{'class':"fsize16 c-333"}).get('title')
                course_url = course_info.find('a',{'class':"fsize16 c-333"}).get('href')
                video = self.get_video_info(course_url,video)
                video_lst.append(video)
                print("获取到课程《%s》，已学习%d%%，总时长%s秒!"%(video['name'],video['percent'],video['totalTime']))
            except ValueError:
                continue
        return video_lst
    
    def _get_current_percent(self,course_info):
        percent = course_info.find('div',{'class':"lev-num-wrap"}).get('title')
        percent = re.findall(r"\d+\.?\d*",percent)
        if len(percent)==0:
            percent = 0
        else:
            percent = float(percent[0])
        return percent
    
    def get_video_timeinfo(self,course_id,kpoint_id,playfromtype):
        time_headers = self.headers
        time_headers['Referer'] = 'http://www.sptce.cn/uc/play/%s/%s'%(course_id,kpoint_id)
        # Referer: http://www.sptce.cn/uc/play/227/707
        params = {'kpointId':kpoint_id,
                  'courseId':course_id,
                  'playFromType':playfromtype}
        time_info = self.session.post('http://www.sptce.cn/front/ajax/checkKpoint',params=params,headers=time_headers,cookies=self.cookies)
        # pattern = re.compile("var databack = \"(.*?),\";")
        time_info_content = time_info.content.decode(time_info.encoding)
        source = re.compile("source:\"(.*?)\"").findall(time_info_content)
        if len(source) == 1:
            source = source[0]
        else:
            return None,None
        player = requests.get(source, stream=True)
        for data in player.iter_content(chunk_size=512):
            if data.find(b'mvhd') > 0:
                index = data.find(b'mvhd') + 4
                time_scale = struct.unpack('>I', data[index + 13:index + 13 + 4])
                durations = struct.unpack('>I', data[index + 13 + 4:index + 13 + 4 + 4])
                duration = durations[0] / time_scale[0]
                break
        return source,duration
  
    def get_video_info(self,course_url,video):
        course_id =  re.findall(r"\d+\.?\d*",course_url)
        if len(course_id) == 0:
            video['courseId'] = None
            return video
        #单个课程的视频地址，课程播放的kpointID，playfromtype参数
        video['courseId'] = course_id[0]
        courseKpointList_headers = self.headers
        courseKpointList_headers['Referer'] = course_url
        courseKpointList_url = 'http://www.sptce.cn/front/ajax/courseKpointList/%s/2'%(video['courseId'])
        ckl_resp = self.session.post(url=courseKpointList_url,headers=courseKpointList_headers,cookies=self.cookies)
        ckl_resp_soup = BeautifulSoup(ckl_resp.content, "html.parser")
     
        #课程的playfromtype参数
        video['playFromType'] = ckl_resp_soup.find('input',{'id':"playFromType"}).get('value')
        #获取课程播放大厅地址及课程kpointIDclass="cou-kscp"
        player_kpointid = ckl_resp_soup.find('a',{'class':"cou-kscp"}).get('id')
        player_kpointid =  re.findall(r"\d+\.?\d*",player_kpointid)
        if len(player_kpointid) == 1:
            video['kpointId'] = player_kpointid[0]
        else:
            video['kpointId'] = None
            return video
        video['play_source'],video['totalTime']  = self.get_video_timeinfo(video['courseId'],video['kpointId'],video['playFromType'])
        return video
    
    def get_courseKpointTimeMsgList(self,video):
        msg_url = "http://www.sptce.cn/kpoint/ajax/courseKpointTimeMsgList/%s"%(video['kpointId'])
        params = {'kpointId':video['kpointId'],
                  'courseId':video['courseId'],}
        msgs = self.session.post(msg_url, params = params,headers=self.headers,cookies=self.cookies)
        if msgs.json()['success'] or msgs.json()['success'] is 'true':
            return msgs.json()['entity']
        else:
            return []
        
    def play_video(self,video):
        '''
        视频学习验证机制（20210325）参考http://www.sptce.cn/static/inxweb/front/course-kpoint-list.js
        
        每隔10s向http://www.sptce.cn/couserStudyHistory/ajax/playertimes发送get请求验证视频播放
        （上面链接代码写这个是post方法，但是浏览器调试显示是get方法）
        参数为kpointId，courseId，playTime（当前播放长度），totalTime（视频总时长）
        向http://www.sptce.cn/kpoint/ajax/courseKpointTimeMsgList/kpointId发出post请求接收视频弹出框信息播（放到10分钟和30分钟）
        参数为kpointId，courseId（这个可能不需要）
        在视频播放到10分钟和30分钟时，需要向http://www.sptce.cn/dialog/ajax/showPage发送post
        参数{dTitle: 提示
             msg: 您已学习10分钟 , 请注意保护视力健康。
             index: 0}
        '''
        # logger.info(f"{video['name']} 开始播放..." )
        print('<',video['name'],">开始播放..."  )
        # http://www.sptce.cn/couserStudyHistory/ajax/playertimes?
        # session.get("http://www.sptce.cn/couserStudyHistory/ajax/playertimes", params=params, headers=headers)
        # percent = float(video['progress'].replace("已观看","").replace("%","").strip())
        msgs = self.get_courseKpointTimeMsgList(video)
        cnt = video['totalTime']*video['percent']/100
        cnt0 = cnt
        while cnt < video['totalTime']:
            sleep_time = 10+random.random()/video['totalTime']
            time.sleep(sleep_time)
            cnt += sleep_time
            if cnt > video['totalTime']:
                cnt =  video['totalTime']
            params = {'kpointId':video['kpointId'],
                      'courseId':video['courseId'],
                      'playTime':cnt, 
                      'totalTime':video['totalTime']}
            history = self.session.post("http://www.sptce.cn/couserStudyHistory/ajax/playertimes", params = params,headers=self.headers,cookies=self.cookies)
            for msg in msgs:
                if msg['id'] and (cnt-cnt0) > float(msg['minute'])*60:
                    msg['id']=False
                    params = {'dTitle': '提示',
                              'msg': msg['content'],
                              'index': 0}
                    self.session.post("http://www.sptce.cn/dialog/ajax/showPage", params = params,headers=self.headers,cookies=self.cookies)
                else:
                    continue
            if history.json()['success'] == True:
                print("\r播放进度为:%d%%" %(cnt*100/video['totalTime']), end='')
        print('<',video['name'],">播放完毕！")
        
    def study_all_courses(self):
        for video in self.get_course_infos():
            try:
                self.play_video(video)
            except:
                continue
        print("恭喜你完成所有课程的学习！")
      
def get_cookie_dict():
    cookie_dict = {}
    cookies = 'sessionid=941b1d48-21a8-4e03-8aa9-04fecde37c52; JSESSIONID=DC42ABB3FDFB0B2B5AAED36C5DADF3A1; webplus_group_000011web_user_login=a1c6fae8371e48dd8ab618984d9fd432;'
    for kv in cookies.split('; '):
        # kv: 'td_cookie=184xxx'
        key = kv.split('=')[0]
        value = kv.split('=')[1]
        cookie_dict[key] = value
    return cookie_dict

if __name__ == "__main__":
    # r_cookies = login()
    cookies = get_cookie_dict()
    session = requests.session()
    courseinfo = CourseInfo(session,headers,cookies)
    courseinfo.study_all_courses()